package com.agg.domain.repository;

import cn.hutool.core.util.ReflectUtil;
import com.agg.core.base.VoidEnum;
import com.agg.core.base.dao.IBaseMapper;
import com.agg.core.base.dto.ExtDTO;
import com.agg.core.base.dto.PaginationDTO;
import com.agg.core.base.po.BasePO;
import com.agg.core.exception.DomainException;
import com.agg.domain.command.BaseCmd;
import com.agg.persist.mybatis.GenericMapper;
import com.agg.persist.xml.EntityMapperRegistry;
import com.agg.persist.xml.mapping.EntityMapper;
import com.agg.persist.xml.mapping.Ref;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public abstract class AbstractRepository {
    @Autowired
    private ApplicationContext context;

    @Resource
    private GenericMapper genericMapper;

    private IBaseMapper mapper;
    /**
     * 缓存bean 的方法
     */
    private final static Map<String,Method> methodMap=new HashMap<>();


    public IBaseMapper getMapper() {
        return mapper;
    }

    public void setMapper(IBaseMapper mapper) {
        this.mapper = mapper;
    }

    /**
     *
     * @param cmd
     * @return
     */
    protected EntityMapper getEntityMapper(BaseCmd cmd){
        EntityMapper em= EntityMapperRegistry.getEntityMapper(cmd.getEmid());
        if(em==null){
            throw new DomainException("error");
        }
        return em;
    }

    protected  <K, E,Ex> Page<K> getByPage(PaginationDTO<K, E,Ex> pagination, String emId) {
        try {
            Integer pageSize=pagination.getSize();
            Integer pageNum=pagination.getCurrent();
            K condition=pagination.getCondition();
            //从缓存中获取要执行的方法
            Method method=methodMap.get(emId);
            if(method==null){
                //从mappr 中获取并缓存
                Method[] methods=mapper.getClass().getMethods();
                for (Method m:methods){
                    if(m.getName().equals("getPage")){
                        method=m;
                        methodMap.put(emId,method);
                        break;
                    }
                }
            }

            Page page=(Page) method.invoke(mapper,new Page<K>(pageNum,pageSize),
                    condition,
                    pagination.getOther(),emId);
            return page;
        }catch (Exception e){
            e.printStackTrace();
            throw  new RuntimeException("操作失败");
        }

    }


    protected  <E> List getList(E entity,ExtDTO dto,String emId) {
        try {
            List list= genericMapper.getList(entity,dto,emId);
            return list;
        }catch (Exception e){
            e.printStackTrace();
            throw  new DomainException("操作失败");
        }
    }

    protected BasePO getById(Serializable id, String emId) {
        try {
            BasePO entity=genericMapper.getById(id,emId);
            return entity;
        }catch (Exception e){
            e.printStackTrace();
            throw  new DomainException( "操作失败",e);
        }
    }


    protected Map<Object,Object> getEntityRefList(Ref ref, List<Object> keys){
        try{
            Object bean=ref.getExecutor();
            Method method=ReflectUtil.getMethodByName(bean.getClass(),ref.getListMethod());
            Map<Object,Object> refDatas=(Map<Object,Object>) method.invoke(bean,keys);
            return refDatas;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new DomainException("获取ref  聚合数据失败");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            throw new DomainException("获取ref  聚合数据失败");
        }
    }

    protected Object getEntityRef(Ref ref, Object entity)  {
        try{
            Object bean=ref.getExecutor();
            Method method= bean.getClass().getDeclaredMethod(ref.getMethod(),bean.getClass());
            Object refData=method.invoke(bean,entity);
            return refData;
        }catch (NoSuchMethodException e){
            e.printStackTrace();
            throw new DomainException("获取ref  聚合数据失败");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            throw new DomainException("获取ref  聚合数据失败");
        } catch (InvocationTargetException e) {
            e.printStackTrace();
            throw new DomainException("获取ref  聚合数据失败");
        }

    }

    protected  Page<Map<String,Object>> loadMapByPage(PaginationDTO<Map<String,Object>, VoidEnum,ExtDTO> pagination,
                                                      String emId){
        try {
            Integer pageSize=pagination.getSize();
            Integer pageNum=pagination.getCurrent();
            Map condition=pagination.getCondition();
            ExtDTO extDTO=  pagination.getOther();
            Page<Map<String,Object>> page= genericMapper.getMapPage(new Page<Map>(pageNum,pageSize),
                    condition,extDTO,emId);
            return page;
        }catch (Exception e){
            throw  new DomainException("操作失败",e);
        }
    }

    protected  Page<Map<String,Object>> loadMapBySqlPage(PaginationDTO<Map<String,Object>,  VoidEnum,ExtDTO> pagination,
                                                      String sqlTmplate){

        Integer pageSize=pagination.getSize();
        Integer pageNum=pagination.getCurrent();
        Map condition=pagination.getCondition();
        ExtDTO extDTO=  pagination.getOther();
        Page<Map<String,Object>> page= genericMapper.getMapBySqlPage(new Page<Map>(pageNum,pageSize),
                condition,extDTO,sqlTmplate);
        return page;

    }

}
